#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import pprint
import StringIO

from utils import _dmsg, _dwarn, _derror, _str2dict, _exec_shell1
from config import Config
import bcache


def disk_file_keyfunc(x):
    try:
        return int(x.split('.')[0])
    except:
        return x


class NodeStat(object):
    def __init__(self):
        self.home = '/opt/fusionstack'
        self.lichd = os.path.join(self.home, 'lich/sbin/lichd')

        self.recovery_opt_path = '/opt/fusionstack/data/recovery'

        self.recovery_dev_path = '/dev/shm/lich4/nodectl/recovery'
        self.recovery_qos_path = '/dev/shm/lich4/nodectl/qos'

        self.diskstat_path = '/dev/shm/lich4/nodectl/diskstat'

    @staticmethod
    def __read_dict(path):
        if os.path.isfile(path):
            val = bcache.read_file(path)
            return _str2dict(val)
        else:
            return {}

    @staticmethod
    def __stat_keys(name, path, keys=None):
        _dwarn('== name %s path %s keys %s' % (name, path, keys))
        if not os.path.isdir(path):
            return

        buf = StringIO.StringIO()
        buf.write('  %10s:' % '')

        if not keys:
            keys = os.listdir(path)

        for key in keys:
            filename = os.path.join(path, key)
            if os.path.isfile(filename):
                val = bcache.read_file(filename)
                buf.write(' %s %s' % (key, val))

        print buf.getvalue()

    @staticmethod
    def __stat_pool(name, path, keys):
        _dwarn('== name %s path %s keys %s' % (name, path, keys))
        if not os.path.isdir(path):
            return

        for pool in os.listdir(path):
            if not os.path.isdir(os.path.join(path, pool)):
                continue

            buf = StringIO.StringIO()
            buf.write('  %-10s: ' % pool)

            for i in keys:
                filename = os.path.join(path, pool, i)
                if os.path.isfile(filename):
                    val = bcache.read_file(filename)
                    buf.write(' %s %s' % (i, val))

            print buf.getvalue()

    @staticmethod
    def __stat_pool_dict(name, path, keys=None, keyfun=None):
        _dwarn('== name %s path %s keys %s' % (name, path, keys))
        if not os.path.isdir(path):
            return

        for pool in os.listdir(path):
            if not os.path.isdir(os.path.join(path, pool)):
                continue

            if not keys:
                keys2 = os.listdir(os.path.join(path, pool))
                # print type(keys2), keys2
                keys2.sort(key=keyfun)
            else:
                keys2 = keys

            _dmsg('  %-10s: ' % pool)

            for key in keys2:
                val = NodeStat.__read_dict(os.path.join(path, pool, key))
                if 'status' in val and val['status'] != 'waiting':
                    _derror('    %-10s %s' % (key, val))
                elif 'online' in val and val['online'] == '0':
                    _derror('    %-10s %s' % (key, val))
                else:
                    _dmsg('    %-10s %s' % (key, val))

    def __stat_recovery_config(self):
        self.__stat_pool("Recovery Config", self.recovery_opt_path,
                                ['scale', 'thread', 'fill_rate', 'disk_fill_rate', 'recovery_total', 'disk_recovery_total'])

    def __stat_recovery_status(self):
        self.__stat_pool("Recovery Status", self.recovery_dev_path, ['interval', 'immediately'])
        print
        self.__stat_pool_dict('Recovery Info', self.recovery_dev_path, keys=['info', 'disk_info'])

    def __stat_recovery_qos(self):
        self.__stat_keys("Recovery Qos", self.recovery_qos_path, keys=None)

    def __stat_disk(self):
        self.__stat_pool_dict('Disk Stat', self.diskstat_path, keys=None, keyfun=disk_file_keyfunc)

    def stat_recovery(self):
        self.__stat_recovery_config()
        print
        self.__stat_recovery_status()
        print
        self.__stat_recovery_qos()
        print
        self.__stat_disk()

    def stat_msgctl(self):
        self.__stat_keys('Msgctl Level', '/dev/shm/lich4/msgctl', ['level', 'backtrace'])
        print
        self.__stat_keys('Msgctl Sub', '/dev/shm/lich4/msgctl/sub', keys=None)

    def stat_release(self):
        out, err = _exec_shell1('%s -v' % self.lichd, retry=1, p=False)
        d = _str2dict(out)
        pprint.pprint(d)
        return d

    def __tool_isvalid(self, tool):
        try:
            out, err = _exec_shell1('which %s' % tool, retry=1, p=False)
            return True
        except:
            return False

    def __file_exists(self, filename):
        return os.path.exists(filename)

    def stat_tools(self):
        tools = [
            'dd', 'lsblk',
            'make-bcache', 'bcache-super-show',
            'etcdctl',
            'lich', 'lich.node',
            'xxx'
            ]
        _dmsg('==Checking Tools:')
        for x in tools:
            exists = self.__tool_isvalid(x)
            if exists:
                _dmsg('  %-40s YES' % x)
            else:
                _derror('  %-40s NO' % x)

        print
        _dmsg('==Checking Files:')
        files = [
            '/opt/MegaRAID/MegaCli/MegaCli64',
            '/opt/fusionstack/lich/sbin/lichd',
        ]
        for x in files:
            exists = self.__file_exists(x)
            if exists:
                _dmsg('  %-40s YES' % x)
            else:
                _derror('  %-40s NO' % x)


if __name__ == '__main__':
    nstat = NodeStat()
    nstat.stat_release()
    nstat.stat_msgctl()
    nstat.stat_release()
